IBX-6773: Fixed loading Bookmarks for non-accessible content items#476
IBX-6773: Fixed loading Bookmarks for non-accessible content items#476
Conversation
bdac332 to
9164daa
Compare
|
9164daa to
ec96060
Compare
src/contracts/Repository/Values/Content/Query/Criterion/IsBookmarked.php
Outdated
Show resolved
Hide resolved
tests/lib/Persistence/Legacy/Filter/CriterionQueryBuilder/Location/BookmarkQueryBuilderTest.php
Outdated
Show resolved
Hide resolved
konradoboza
left a comment
There was a problem hiding this comment.
Did you make sure none of the deprecated classes are still in use?
|
@konradoboza : FYI : Had to add related PR : ibexa/admin-ui#1835 |
| $this->assertEquals($contactUsLocationId, $afterSwap->items[0]->id); | ||
| $this->assertEquals($beforeSwap->items[1]->id, $afterSwap->items[1]->id); |
There was a problem hiding this comment.
Why this change? It's not clear at first glance.
There was a problem hiding this comment.
@konradoboza
The testcase initially tests swapping two locations that are both bookmarked.
I modified the test to check behavior when 1 location is bookmarked and the other is not
…n - PHPStand and BookmarkQueryBuilder
…n - PHPStand and Bookmark\IdSortClauseQueryBuilder
…n - Added more Strict typing
…tion/BookmarkQueryBuilderTest.php Co-authored-by: Konrad Oboza <konrad.oboza@ibexa.co>
78b2c3b to
648ac3e
Compare
|
PR rebased. |
konradoboza
left a comment
There was a problem hiding this comment.
Can we have some integration test scenarion within Ibexa\Tests\Integration\Core\Repository\BookmarkServiceTest?
@konradoboza : Yeah, did a search and found nothing except the use in test: Should those tests be marked deprecated somehow to ? |
|
Not at all. We just change the usage of the method being deprecated from day one. Tests will be adjusted accordingly on the actual removal of the code in question. |
Co-authored-by: Konrad Oboza <konrad.oboza@ibexa.co>
|
#476 (review) please take also this into account. |
Those integration tests uses BookmarkService. And the BookmarkService is already updated to use the filter instead of the deprecated functions from persistence layer. But I added also a test for count ( BookmarkServiceTest::testCountBookmarks() ) in 5fd0eb2 Edit: with a fixup : 993e850 |
…cationService::count()
…cationService::count()
… and LocationService::count()
Co-authored-by: Konrad Oboza <konrad.oboza@ibexa.co>
|
| /** | ||
| * Loads bookmarks owned by user. | ||
| * | ||
| * @deprecated The "Handler::loadUserBookmarks()" method is deprecated, will be removed in 6.0.0. Use "LocationService::find()" and "Criterion\IsBookmarked" instead. |
There was a problem hiding this comment.
Deprecating it in 6.0 is fine for now, but the annotation format is not correct and most likely it's gonna affect or even crash phpDocumentor ;-)
Please see PHP Conventions: Deprecation standards.
| * Supported operators: | ||
| * - EQ: matches against a unique user id | ||
| */ | ||
| final class IsBookmarked extends Criterion implements FilteringCriterion |
There was a problem hiding this comment.
Extending criterion means that this would be available not just for filtering but for search too. Hence it would require implementing handlers for all supported search engines.
Filtering was supposed initially to mirror search service, so there are no examples of Filtering Criteria that are not Search Criteria at the same time, but the intention of Filtering was that it can exist as a separate concepts for data which are not supposed to be a part of Search Index but a database.
ATM it's possible to use it with search and get the following fatal error at runtime:
Ibexa\Contracts\Core\Repository\Exceptions\NotImplementedException : Intentionally not implemented: No visitor available for: Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\IsBookmarked with operator =
If it doesn't rely on Criterion, the error should appear on at least static analysis level, which provides better DX.
| * @deprecated The "BookmarkHandler::loadUserBookmarks()" method is deprecated, will be removed in 6.0.0. Use "LocationService::find()" and "Criterion\IsBookmarked" instead. | ||
| * | ||
| * {@inheritdoc} |
There was a problem hiding this comment.
Please don't repeat the same message here. It should be present on the interface only.
In fact, you can drop the entire block because doc inheritance is done by default (it's legacy annotation here).
| @@ -146,6 +148,8 @@ public function loadUserBookmarks(int $userId, int $offset = 0, int $limit = -1) | |||
| } | |||
|
|
|||
| /** | |||
| * @deprecated The "DoctrineDatabase::countUserBookmarks()" method is deprecated, will be removed in 6.0.0. Use "LocationService::count()" and "Criterion\IsBookmarked" instead. | |||
| * | |||
| @@ -66,6 +71,9 @@ public function loadUserBookmarks(int $userId, int $offset = 0, int $limit = -1) | |||
| } | |||
| } | |||
|
|
|||
| /** | |||
| * @deprecated The "ExceptionConversion::countUserBookmarks()" method is deprecated, will be removed in 6.0.0. Use "LocationService::count()" and "Criterion\IsBookmarked" instead. | |||
| /** | ||
| * @deprecated The "ExceptionConversion::loadUserBookmarks()" method is deprecated, will be removed in 6.0.0. Use "LocationService::find()" and "Criterion\IsBookmarked" instead. | ||
| * | ||
| * @return array |
There was a problem hiding this comment.
This PHPDoc return doesn't provide any extra value. It should be documented as at least array<string, mixed> but on the interface (or abstract) level.
| */ | ||
| final class IsBookmarked extends Criterion implements FilteringCriterion | ||
| { | ||
| public function __construct(int $value) |
There was a problem hiding this comment.
Important
API design remark
Typically you'd want here bool $isBookmarked = true. Semantically IsBookmarked(14) doesn't read well and is rather not expected with the verb Is.
User ID value should be part of a handler (query builder), not a criterion. That being said, I see you provided a case for IsBookmark of user X or user Z. It's a bit out of scope of the usage of this criterion, but if you indeed want such flexibility, user ID should be an optional 2nd argument (by default null, taken from current user in query builder).
| ); | ||
|
|
||
| /** @var \Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\IsBookmarked $criterion */ | ||
| $value = $criterion->value; |
There was a problem hiding this comment.
As described earlier, this should be part of the logic here, not user input by default. Inject PermissionResolver and get current user ID
|
|
||
| $list = new BookmarkList(); | ||
| $list->totalCount = $result->totalCount; | ||
| $list->items = $result->locations; |
There was a problem hiding this comment.
locations is a magic property, which using of should be avoided due to performance. You should rather do iterator_to_array here.
| /** @var \Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\IsBookmarked $criterion */ | ||
| $value = $criterion->value; | ||
|
|
||
| if (\is_array($value)) { | ||
| if (!isset($value[0])) { | ||
| throw new \InvalidArgumentException('IsBookmarked criterion value must contain userId at index 0.'); | ||
| } | ||
| $value = $value[0]; | ||
| } | ||
|
|
||
| return $queryBuilder->expr()->eq( | ||
| 'bookmark.user_id', | ||
| $queryBuilder->createNamedParameter( | ||
| (int)$value, | ||
| ParameterType::INTEGER | ||
| ) | ||
| ); |
There was a problem hiding this comment.
Following the API design remark, This could be either:
$userId = $criterion->getUserId() ?? $this->permissionResolver->getCurrentUserReference()->getUserId();or simply
$userId = $this->permissionResolver->getCurrentUserReference()->getUserId();PermissionResolver should be injected via constructor.
As for boolean value of is or is not bookmarked, I'd probably use ternary expression based on $criterion->isBookmarked() getter and call neq or eq depending on the value.



v4.6Related PRs:
loadBookmarkscall with Repository filtering requirements admin-ui#1835Description:
If user bookmark some location which he later looses access too, then the bookmark list in admin-ui fails with an exception.
Simply fixing
BookmarkService::loadBookmarks()would be easy. The problem is to implementcountUserBookmarks()in persistence layer and having it taking into account user permissions so that BC would be kept.Talked with Adam on how to solve this without breaking BC and he suggested implementing it using filtering
The Bookmark filter will only work with location filtering (
LocationService::find()), not with content (ContentService::find())This is a port of ezsystems/ezplatform-kernel#408 which was not approved and merge in time before 3.3 went EOL.
For QA:
Read ticket for info on how to reproduce
Documentation:
Documentation for the new filter needs to be made, indeed